{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "---\n",
    "title: Variables\n",
    "order: 3\n",
    "sidebar_position: 3\n",
    "description: Introduction to Mojo variables.\n",
    "css: /static/styles/page-navigation.css\n",
    "website:\n",
    "  open-graph:\n",
    "    image: /static/images/mojo-social-card.png\n",
    "  twitter-card:\n",
    "    image: /static/images/mojo-social-card.png\n",
    "---"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A variable is a name that holds a value or object. All variables in Mojo are mutable—their value can be changed. (If you want to define a constant value that can't change at runtime, see the \n",
    "[`alias` keyword](/mojo/manual/parameters/index.html#alias-named-parameter-expressions).)\n",
    "\n",
    ":::note\n",
    "\n",
    "Mojo formerly supported the `let` keyword for declaring immutable variables.\n",
    "This has been removed to simplify the language, and for other reasons\n",
    "[discussed\n",
    "elsewhere](https://github.com/modularml/mojo/blob/main/proposals/remove-let-decls.md).\n",
    "To simplify the migration of older code, `let` declarations are currently\n",
    "supported, but function the same as `var` declarations.\n",
    "\n",
    ":::"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Undeclared variables\n",
    "\n",
    "Within a `def` function or a REPL environment, you can create a variable with\n",
    "just a name and a value. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "name = \"Sam\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A variable declared without `var` follows s.\n",
    "\n",
    "\n",
    ":::note\n",
    "\n",
    "Undeclared variables are not allowed in an `fn` function or as a struct\n",
    "field.\n",
    "\n",
    ":::"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Declared variables\n",
    "\n",
    "You can declare a variable with the `var` keyword. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "var name = \"Sam\"\n",
    "var user_id: Int"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `name` variable is initialized to the string \"Sam\". The `user_id` variable is uninitialized, but it has a declared type, `Int` for an integer value. All\n",
    "declared values are typed—either explicitly with a \n",
    "[type annotation](#type-annotations) or implicitly when they're initialized with a value.\n",
    "\n",
    "Since declared variables are strongly typed, you can't assign a variable a\n",
    "value of a different type, unless those types can be \n",
    "[implicitly converted](#implicit-type-conversion). For example, this code will not compile:\n",
    "\n",
    "```mojo\n",
    "var user_id: Int = \"Sam\"\n",
    "```\n",
    "\n",
    "In addition to typing, declared variables also follow \n",
    "[lexical scoping](#variable-scopes), unlike undeclared variables.\n",
    "\n",
    "Finally, using `var` helps prevent runtime errors caused by typos. For example,\n",
    "if you misspell the name of an [undeclared variable](#undeclared-variables),\n",
    "Mojo simply instantiates a new variable using the misspelled name. But when all\n",
    "mutable variables must be first declared with `var` (which is the case inside\n",
    "an `fn` function), then misspellings such as the following are caught by the\n",
    "compiler:\n",
    "\n",
    "```mojo\n",
    "var name = \"Sam\"\n",
    "# Somewhere later...\n",
    "nane = \"Sammy\"  # This is not allowed in an `fn` function\n",
    "```\n",
    "\n",
    "Although you can use `var` in a `def` function, this benefit is\n",
    "realized only when used inside an `fn` function, where the Mojo compiler will\n",
    "flag undeclared variables (such as the above `nane`) as unknown declarations.\n",
    "\n",
    "\n",
    ":::note\n",
    "\n",
    "When using Mojo in a REPL environment, top-level variables (variables\n",
    "outside a function or struct) do not require `var` declarations.\n",
    "\n",
    ":::"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Type annotations"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Although Mojo supports dynamic variable types (it can infer a value type at\n",
    "runtime), it also supports static type annotations on variables. This enables\n",
    "strong compile-time type checking for variables, which can make your code more\n",
    "predictable, manageable, and secure (especially when combined with type\n",
    "checking in [`fn` functions](/mojo/manual/functions.html#fn-functions)).\n",
    "\n",
    "To specify the type for a variable, add a colon followed by the type name:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "var name: String = \"Sam\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This way, `name` can never be assigned a value that's not a string (or that\n",
    "cannot be [implicitly converted](#implicit-type-conversion) to a string).\n",
    "\n",
    ":::note\n",
    "\n",
    "You must declare a variable with `var` to use type annotations.\n",
    "\n",
    ":::\n",
    "\n",
    "If a type has a constructor with just one argument, you can initialize it in\n",
    "two ways:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "var name1: String = \"Sam\"\n",
    "var name2 = String(\"Sam\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Both of these lines invoke the same constructor to create a `String` from a\n",
    "`StringLiteral`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Late initialization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using type annotations allows for late initialization. For example, notice here\n",
    "that the `z` variable is first declared with just a type, and the value is\n",
    "assigned later:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn my_function(x: Int):\n",
    "    var z: Float32\n",
    "    if x != 0:\n",
    "        z = 1.0\n",
    "    else:\n",
    "        z = foo()\n",
    "    print(z)\n",
    "\n",
    "fn foo() -> Float32:\n",
    "    return 3.14"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::note\n",
    "\n",
    "Late initialization works only if the variable is declared with a\n",
    "type.\n",
    "\n",
    ":::"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Implicit type conversion"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some types include built-in type conversion (type casting) from one type into\n",
    "its own type. For example, if you assign a number to a `String`, it creates the\n",
    "string `\"1\"` instead of a compiler error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "var number: String = 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As shown above, value assignment can be converted into a constructor call if the \n",
    "target type has a constructor that takes a single argument that matches the\n",
    "value being assigned. So, this code uses the \n",
    "[`String`](/mojo/stdlib/builtin/string.html#string) constructor that takes an\n",
    "integer: `__init__(inout self, num: Int)`.\n",
    "\n",
    "Implicit conversion follows the logic of [overloaded\n",
    "functions](/mojo/manual/functions.html#overloaded-functions), because\n",
    "that's exactly what's happening here: assigning a number to a `String` variable\n",
    "is exactly the same as this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "var number = String(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Thus, if you call a function that requires an argument of a certain type (such\n",
    "as `String`), you can pass in any value as long as that value type can\n",
    "implicitly convert to the required type (using one of the type's overloaded\n",
    "constructors).\n",
    "\n",
    "For example, you can pass an `Int` to a function that expects a `String`,\n",
    "because `String` includes a constructor that takes an `Int`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn take_string(version: String):\n",
    "    print(version)\n",
    "\n",
    "fn pass_integer():\n",
    "    var version: Int = 1\n",
    "    take_string(version)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For more details on implicit conversion, see \n",
    "[Constructors and implicit \n",
    "conversion](/mojo/manual/lifecycle/life/#constructors-and-implicit-conversion)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Variable scopes\n",
    "\n",
    "Variables declared with `var` are bound by *lexical scoping*. This\n",
    "means that nested code blocks can read and modify variables defined in an\n",
    "outer scope. But an outer scope **cannot** read variables defined in an\n",
    "inner scope at all.\n",
    "\n",
    "For example, the `if` code block shown here creates an inner scope where outer\n",
    "variables are accessible to read/write, but any new variables do not live\n",
    "beyond the scope of the `if` block:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "num: 10\n",
      "num: 20\n",
      "num: 10\n",
      "dig: 2\n"
     ]
    }
   ],
   "source": [
    "def lexical_scopes():\n",
    "    var num = 10\n",
    "    var dig = 1\n",
    "    if True:\n",
    "        print(\"num:\", num)  # Reads the outer-scope \"num\"\n",
    "        var num = 20        # Creates new inner-scope \"num\"\n",
    "        print(\"num:\", num)  # Reads the inner-scope \"num\"\n",
    "        dig = 2             # Edits the outer-scope \"dig\"\n",
    "    print(\"num:\", num)      # Reads the outer-scope \"num\"\n",
    "    print(\"dig:\", dig)      # Reads the outer-scope \"dig\"\n",
    "\n",
    "lexical_scopes()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the `var` statement inside the `if` creates a **new** variable with the same name as the outer variable. This prevents the inner loop from accessing the outer `num` variable. (This is called \"variable shadowing,\" where the inner scope variable hides or \"shadows\" a variable from an outer scope.)\n",
    "\n",
    "The lifetime of the inner `num` ends exactly where the `if` code block ends,\n",
    "because that's the scope in which the variable was defined.\n",
    "\n",
    "This is in contrast to undeclared variables (those without the `var`\n",
    "keyword), which use **function-level scoping** (consistent with Python variable\n",
    "behavior). That means, when you change the value of an undeclared variable\n",
    "inside the `if` block, it actually changes the value for the entire function.\n",
    "\n",
    "For example, here's the same code but *without* the `var` declarations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "def function_scopes():\n",
    "    num = 1\n",
    "    if num == 1:\n",
    "        print(num)   # Reads the function-scope \"num\"\n",
    "        num = 2      # Updates the function-scope variable\n",
    "        print(num)   # Reads the function-scope \"num\"\n",
    "    print(num)       # Reads the function-scope \"num\"\n",
    "\n",
    "function_scopes()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, the last `print()` function sees the updated `num` value from the inner\n",
    "scope, because undeclared variables (Python-style variables) use function-level\n",
    "scope (instead of lexical scope)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Mojo",
   "language": "mojo",
   "name": "mojo-jupyter-kernel"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "mojo"
   },
   "file_extension": ".mojo",
   "mimetype": "text/x-mojo",
   "name": "mojo"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
